<!DOCTYPE html>
<html>  
<head>
    <title>液体波浪动画</title>
    <meta charset="UTF-8">
    <style>
        body{
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        canvas{
            margin-left: -40px;
        }
        span{
            height: 7px;
            width: 20px;
            display: inline-block;
            cursor: pointer;
            position: absolute;
            top: 0;
                    transition: height 0.2s;
                 -o-transition: height 0.2s;
               -moz-transition: height 0.2s;
            -webkit-transition: height 0.2s;

        }
        span:hover{
            height: 12px;
        }
        #blue{
            background-color: #367aec;
            left: 30px;
        }
        #purple{
            background-color: #f727d2;
            left: 50px;
        }
        #black{
            background-color: #000000;
            left: 70px;
        }
        #container{
            width: 100%;
        }      
    </style>
</head>
<body>
    <div id="container">
        <canvas id="canvas"></canvas>
        <span id="blue" onClick="blue()"></span>
        <span id="purple" onClick="purple()"></span>
        <span id="black" onClick="black()"></span>
    </div>
    <script>
        var canvas,ctx;
        var vertexes = [];
        var diffPt = [];
        var autoDiff = 1000;
        var verNum = 250;
        var canvasW = window.innerWidth + 40;
        //添加事件监听器
        var addListener = function( e, str, func ) {
            if( e.addEventListener ) {
                e.addEventListener( str, func, false );
            }else if( e.attachEvent ) {
                e.attachEvent( "on" + str, func );
            }else {
                
            }
        };

        //window 加载 完成执行 init() 初始化函数
        addListener(window,"load",init);

        //可使窗口改变时执行函数
        function resize(){
            canvasW = document.getElementById('container').offsetWidth + 40;
            //向 initCanvas（初始化Canvas）传参 宽度和高度
            initCanvas(canvasW,window.innerHeight);
                var cW = canvas.width;      //canvas宽度
                var cH = canvas.height;     //canvas高度
                for(var i = 0;i < verNum;i++){
                    vertexes[i] = new Vertex(cW / (verNum -1) * i , cH / 2,cH/2);
                }
                initDiffPt();               //初始化 DiffPt 数组
            var win_3 = window.innerWidth/3;
        }

        //初始化函数
        function init(){
            resize();
            var FPS = 30;
            var interval = 1000 / FPS >> 0;     //取整
            //每隔 interval 时间执行 update()
            var timer = setInterval(update, interval);
            //监控(DOMMouseScroll FF支持)鼠标滚轮事件，如果改变则执行  wheelHandler()
            if (window.addEventListener) addListener(window,"DOMMouseScroll",wheelHandler);
            //监控鼠标滚轮事件，如果改变则执行  wheelHandler()
            addListener(window,"mousewheel",wheelHandler);
            //监听可视窗口改变
            addListener(window,"resize",resize);

            //鼠标点击时执行
            canvas.onmousedown = function(e){
                //鼠标获取点击位置
                var mouseX,mouseY;
                if (e) {
                    mouseX = e.pageX;
                    mouseY = e.pageY;
                } else {
                    mouseX = event.x + document.body.scrollLeft;
                    mouseY = event.y + document.body.scrollTop;
                }
                //点击位置在屏幕横向中心Y轴坐标正负50之间
                if(window.innerHeight/2 - mouseY < 50 && window.innerHeight/2 - mouseY > -50){
                    autoDiff = 600;   //控制波浪大小
                    if(mouseX < canvas.width - 2){
                        xx = 1 + Math.floor((verNum - 2) * mouseX / canvas.width);
                        diffPt[xx] = autoDiff;
                    }
                }
            }
        }

        //滚轮函数
        var wheelHandler = function(e) {
            var s = ( e.detail ) ? -e.detail : e.wheelDelta;
            s > 0 ? ( dd > 15 ? dd-- :  dd=dd) : ( dd < 50 ? dd++ : dd=dd );
        };

        //初始化 DiffPt 数组函数
        function initDiffPt(){
            for(var i = 0;i < verNum;i++)
               diffPt[i]= 0;
        }
        var xx = 150;
        var dd = 15;

        //更新函数
        function update(){
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            autoDiff -= autoDiff*0.9;
            diffPt[xx] = autoDiff;
            //左侧
            //（核心 Code）差分，使得每个点都是上一个点的下一次的解，由于差分函数出来的解是一个曲线，且每次迭代后，曲线相加的结果形成了不断地波浪
            for(var i=xx-1;i>0;i--){
                var d = xx-i;
                if(d > dd)d=dd;
                diffPt[i] -= (diffPt[i]-diffPt[i+1])*(1-0.01*d);
                // console.log(diffPt[i])
            }
            //右侧
            for(var i=xx+1;i<verNum;i++){
                var d = i-xx;
                if(d > dd)d=dd;
                diffPt[i] -= (diffPt[i]-diffPt[i-1])*(1-0.01*d);
            }
            
            //更新点Y坐标
            for(var i = 0;i < vertexes.length;i++){
                vertexes[i].updateY(diffPt[i]);
            }
            draw(); //绘制 Canvas
        }

        var color1 = "#6ca0f6";
        var color2 = "#367aec";

        //Canvas 绘制
        function draw(){
            //绘制上半部
            // ctx.beginPath();
            // ctx.moveTo(0,window.innerHeight);
            // ctx.fillStyle = color1;     //填充颜色 color1
            // ctx.lineTo(vertexes[0].x,vertexes[0].y);
            // for(var i = 1;i < vertexes.length;i++){
            //     ctx.lineTo(vertexes[i].x,vertexes[i].y);
            // }
            // ctx.lineTo(canvas.width,window.innerHeight);
            // ctx.lineTo(0,window.innerHeight);
            // ctx.fill();

            //绘制下半部
            ctx.beginPath();
            ctx.moveTo(0,window.innerHeight);
            ctx.fillStyle = color2;     //填充颜色 color2
            ctx.lineTo(vertexes[0].x+15,vertexes[0].y+5);
            for(var i = 1;i < vertexes.length;i++){
                ctx.lineTo(vertexes[i].x+15,vertexes[i].y+5);
            }
            ctx.lineTo(canvas.width,window.innerHeight);
            ctx.lineTo(0,window.innerHeight);
            ctx.fill();
            
            ctx.fillStyle = "#888";       //填充颜色
            ctx.font = "14px Georgia";    //文本大小/字体
            ctx.textBaseline = "top";     //文本对齐方式

            //绘制文本/位置
            ctx.fillText("点击该液体的表面",70,canvas.height/2-20);
            ctx.fillStyle = "#fff";       //填充颜色
            ctx.fillText("用鼠标滚轮来改变粘度",70,canvas.height/2+15);
            ctx.fillText("滚轮改变粘度 / Viscosity:"+((dd-15)*20/7).toFixed(2)+"%",70,canvas.height-20);
        }
        //初始化 Canvas 高度/宽度
        function initCanvas(width,height){
            canvas = document.getElementById("canvas");
            canvas.width = width;
            canvas.height = height;
            ctx = canvas.getContext("2d");
        }

        //顶点函数
        function Vertex(x,y,baseY){
            this.baseY = baseY;
            this.x = x;
            this.y = y;
            this.vy = 0;
            this.targetY = 0;
            this.friction = 0.15;
            this.deceleration = 0.95;
        }
            
        Vertex.prototype.updateY = function(diffVal){
            this.targetY = diffVal + this.baseY;
            this.vy += this.targetY - this.y
            this.y += this.vy * this.friction;
            this.vy *= this.deceleration;
        }

        //点击后，改变颜色变量
        var blue = function(){
            color1 = "#6ca0f6";
            color2 = "#367aec";
        }
        var black = function(){
            color1 = "#595959";
            color2 = "#000000";
        }
        var purple = function(){
            color1 = "#ff92ec";
            color2 = "#f727d2";
        }
    </script>
</body>
</html>